home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C++
/
Frameworks
/
Sprocket Framework DR2
/
Sprocket Framework
/
SprocketMain.cp
< prev
next >
Wrap
Text File
|
1996-06-15
|
22KB
|
880 lines
/*
File: SprocketMain.cp
Project: Sprocket Framework 1.1 (DR2), released 6/15/96
Contains: The “guts” of a Macintosh application.
To Do: No known problems or bugs
Sprocket Major Contributors:
----------------------------
Dave Falkenburg, producer of Sprocket 1.0
Bill Hayden, producer of Sprocket 1.1
Steve Sisak, producer of the upcoming Sprocket 2.0
Pete Alexander Steve Falkenburg Randy Thelen
Eric Berdahl Nitin Ganatra Chris K. Thomas
Marshall Clow Dave Hershey Leonard Rosenthal
Tim Craycroft Dave Mark Dean Yu
David denBoer Gary Powell
Cameron Esfahani Jon Summers Apple Computer, Inc.
Comments, Additions, or Corrections:
------------------------------------
Bill Hayden, Nikol Software <nikol@codewell.com>
*/
#include "Sprocket.h"
#include <limits.h> // For LONG_MAX
#ifndef __GESTALT__
#include <Gestalt.h>
#endif
#include <Menus.h>
#include <Devices.h>
#include <DiskInit.h>
#include <Threads.h>
#include <Traps.h>
#include <Speech.h>
#include <SpeechRecognition.h>
#include <AppleGuide.h>
#ifndef __CODEFRAGMENTS__
#include "CodeFragments.h"
#endif
#if qInlineInputAware
#include <TextServices.h>
#include <TSMTE.h>
#endif
#if qUseQuickDrawGX
#include <GXEnvironment.h>
#include <GXGraphics.h>
#include <GraphicsLibraries.h>
#include <GXPrinting.h>
#if qUseQuickDrawGXDebugging
#include <GraphicsDebugLibrary.c>
#endif
#endif
#if qUseQC
#include "QCAPI.h"
#endif
#include "StandardMenus.h"
#include "UDialog.h"
#include "Window.h"
#include "SplashWindow.h"
#include "AEHandling.h"
#include "LinkedList.h"
// Function Prototypes
void main(void);
void MainEventLoop(void);
void HandleMouseDown(TWindow * topWindowObj, EventRecord * anEvent);
void HandleClose(WindowRef aWindow);
void HandleMenu(TWindow * topWindow, long menuCode);
// Globals
Boolean gDone = false;
TMenuBar * gMenuBar = nil;
TSplashWindow * gSplashWindow = nil;
long gSystemVersion = 0;
Boolean gHasColorQuickdraw = false;
Boolean gHasThreadManager = false;
Boolean gHasDragManager = false;
Boolean gHasAppleScript = false;
Boolean gHasDisplayManager = false;
Boolean gHasSpeechManager = false;
Boolean gHasSpeechRecognitionManager = false;
Boolean gHasAppleGuide = false;
#if qAOCEAware
Boolean gHasAOCE = false;
#endif
#if qInlineInputAware
Boolean gHasTextServices = false;
Boolean gHasTSMTE = false;
Boolean TSMEventWrapperForKotoeri(EventRecord *anEvent);
#endif
#if qUseQuickDrawGX
Boolean gHasQuickDrawGX = false;
long gQuickDrawGXVersion = 0;
long gQuickDrawGXPrintingVersion = 0;
gxGraphicsClient gQuickDrawGXClient;
#endif
GrafPtr gWindowManagerPort;
Rect gDeskRectangle;
RgnHandle gMouseRegion = nil;
TLinkedList* gCommandQueue;
// Values that can be adjusted by other application code to change
// the behavior of the MainEventLoop.
//
// Rules of thumb:
//
// Increase gXXXRunQuantum (and decrease gXXXSleepQuantum) when:
// The application has many threads running that need time
//
// Decrease gXXXRunQuantum when:
// Sending AppleEvents to other applications
// Launching other applications
// Running in the background
unsigned long gForegroundRunQuantum = 0;
unsigned long gForegroundSleepQuantum = GetCaretTime();
unsigned long gBackgroundRunQuantum = 0;
unsigned long gBackgroundSleepQuantum = LONG_MAX;
// Globals used to “tune” the performance of MainEventLoop
// (assume we’ll be starting in the foreground)
static unsigned long gRunQuantum = gForegroundRunQuantum;
static unsigned long gSleepQuantum = gForegroundSleepQuantum;
#if GENERATINGPOWERPC
#ifndef __MWERKS__
QDGlobals qd;
#endif
#endif
/*****************************************************************************/
void main(void)
{
long feature;
MaxApplZone();
MoreMasters();
MoreMasters();
MoreMasters();
MoreMasters();
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs(nil);
#if qUseQC
if (QCInstalled() == noErr)
QCActivate(nil);
#endif
if (GetToolTrapAddress(_Unimplemented) == GetOSTrapAddress(_Gestalt))
ErrorAlert(kCoreErrorStrings, kUnsupportedSystemSoftware, true);
Gestalt(gestaltSystemVersion, &gSystemVersion);
if (Gestalt(gestaltQuickdrawFeatures,&feature) == noErr)
gHasColorQuickdraw = ((feature & (1 << gestaltHasColor)) != 0);
gSplashWindow = new TSplashWindow;
// Check for and Initialize QuickDraw GX early on to avoid heap fragmentation
#if qUseQuickDrawGX
// Check for and initialize QuickDrawGX
if (Gestalt(gestaltGXVersion, &gQuickDrawGXVersion) == noErr)
{
if (Gestalt(gestaltGXPrintingMgrVersion, &gQuickDrawGXPrintingVersion) == noErr)
{
#if GENERATINGCFM
if ((Ptr) GXEnterGraphics != (Ptr) kUnresolvedCFragSymbolAddress)
#endif
gHasQuickDrawGX = true;
}
}
if (gHasQuickDrawGX)
{
// Initialize the graphics and printing environments.
// For additional details see "IM: QD GX Environment & Utilities."
// We let QuickDraw GX look for a resource of type 'gasz' with an ID of 0.
// GX uses the first long word of that resource as the graphics heap size.
// To determine the memory requirements of your graphics client heap see:
// “IM: QD GX Environment & Utilities pp2-8,2-9”
// NOTE: If your application does not provide this resource,
// QuickDraw GX version 1.0 uses a default size of 600 KB.
gQuickDrawGXClient = GXNewGraphicsClient(nil, kUseGraphicsSizeResource, kAllowGXToExtendGraphicsHeap);
if (gQuickDrawGXClient)
{
// NOTE: GXNewGraphicsClient() does not allocate memory to the heap
// until GXEnterGraphics() is called, so go ahead and call it now
// while we have a chance to deal with things nicely.
//
// NOTE: GXEnterGraphics() should only fail if there is not enough memory.
GXEnterGraphics();
if (GXGetGraphicsError(nil) == noErr)
{
#if qUseQuickDrawGXDebugging
// If qUseQuickDrawGXDebugging = true, enable on GX Validation and graphics library errors & notices.
// NOTES from Jon Summers:
// As you increase the amount of validation, drawing speed will SLOW
// down due to all of the internal checking. Also, if you play with
// settings enough validation seems to become inconsistent
GXSetValidation( // gxInternalValidation |
// gxAllObjectValidation |
// gxApHeapValidation |
gxPublicValidation); // check parameters to public routines
// This functionality will only work with the "debugging" version of QuickDraw GX.
// If you don't have the debugging version installed, these functions will not work.
SetGraphicsLibraryErrors();
SetGraphicsLibraryNotices();
#endif
if (GXInitPrinting() != noErr) // See IM: QuickDraw GX Printing
{
// We couldn’t initialize printing, so clean up pretend GX isn’t around
// ••• For safety’s sake, we’ll probably want to bail here.
if (gQuickDrawGXClient)
GXDisposeGraphicsClient(gQuickDrawGXClient);
gHasQuickDrawGX = false;
}
}
}
}
//if (gQuickDrawGXClient)
//InitCommonColors(); // Initialize the CommonColors Library.
#if qRequireQuickDrawGX
else
ErrorAlert(kCoreErrorStrings, kNeedsQuickdrawGX, false);
#endif // qRequireQuickDrawGX
#endif // qUseQuickDrawGX
if ((Gestalt(gestaltAppleEventsAttr,&feature) == noErr) &&
(feature & (1 << gestaltAppleEventsPresent)))
{
// Figure out if we need to do AppleEvent recording
gHasAppleScript = ((feature & (1 << gestaltScriptingSupport)) != 0);
}
else
ErrorAlert(kCoreErrorStrings, kUnsupportedSystemSoftware, true);
if ((Gestalt(gestaltHelpMgrAttr, &feature) == noErr) && (feature & (1 << gestaltAppleGuidePresent)))
{
gHasAppleGuide = true;
}
#if qInlineInputAware
if ((Gestalt(gestaltTSMgrVersion,&feature) == noErr) && (feature >= 1))
{
gHasTextServices = true;
if (Gestalt(gestaltTSMTEAttr, &feature) == noErr)
gHasTSMTE = (feature & (1 << gestaltTSMTEPresent));
if (InitTSMAwareApplication() != noErr)
{
gHasTextServices = false;
gHasTSMTE = false;
}
}
#endif
if (Gestalt(gestaltThreadMgrAttr,&feature) == noErr)
{
#if GENERATINGCFM
// If running under the CFM, make sure that we not only have the
// Thread Manager, but also the shared library, too.
// Because of the wonders of weak linking and out of memory errors
// we need to also check to make sure that an entrypoint in the library
// is there, too.
if ((Ptr) NewThread != (Ptr) kUnresolvedCFragSymbolAddress)
gHasThreadManager = ((feature & ((1 << gestaltThreadMgrPresent) | (1 << gestaltThreadsLibraryPresent))) != 0);
#else
gHasThreadManager = ((feature & (1 << gestaltThreadMgrPresent)) != 0);
#endif
}
#if qRequireThreadManager
if (gHasThreadManager == false)
ErrorAlert(kCoreErrorStrings, kNeedsThreadManager, true);
#endif
// Check for and install Drag Manager callbacks
if (Gestalt(gestaltDragMgrAttr,&feature) == noErr)
{
#if GENERATINGCFM
// If running under the CFM, make sure that we not only have the
// Thread Manager, but also the shared library, too.
if ((Ptr) NewDrag != (Ptr) kUnresolvedCFragSymbolAddress)
gHasDragManager = ((feature & ((1 << gestaltDragMgrPresent) | (1 << gestaltPPCDragLibPresent))) != 0);
#else
gHasDragManager = ((feature & (1 << gestaltDragMgrPresent)) != 0);
#endif
if (gHasDragManager)
{
InstallTrackingHandler(NewDragTrackingHandlerProc(CallWindowDragTrackingHandler),(GrafPtr) nil,nil);
InstallReceiveHandler(NewDragReceiveHandlerProc(CallWindowDragReceiveHandler),(GrafPtr) nil,nil);
}
}
// Check for Display Manager
if (Gestalt(gestaltDisplayMgrAttr,&feature) == noErr)
gHasDisplayManager = ((feature & (1 << gestaltDisplayMgrPresent)) != 0);
#if qAOCEAware && qPowerTalkSystemSupport
// Check for and initialize AOCE Standard Mail package if it exists
if ((Gestalt(gestaltSMPMailerVersion,&feature) == noErr) && (feature != 0))
{
#if GENERATINGCFM
if ((Ptr) SMPInitMailer != (Ptr) kUnresolvedCFragSymbolAddress)
gHasAOCE = (SMPInitMailer(kSMPVersion) == noErr);
#else
gHasAOCE = (SMPInitMailer(kSMPVersion) == noErr);
#endif
}
#endif
// Check for and initialize the Speech Manager
if ((Gestalt(gestaltSpeechAttr, &feature) == noErr) && (feature != 0))
{
#if GENERATINGCFM
// If running under the CFM, make sure that we not only have the
// Speech Manager, but also the shared library, too.
// Because of the wonders of weak linking and out of memory errors
// we need to also check to make sure there is an entrypoint in the library, too.
if ((Ptr) CountVoices != (Ptr) kUnresolvedCFragSymbolAddress)
gHasSpeechManager = ((feature & ((1 << gestaltSpeechMgrPresent) | (1 << gestaltSpeechHasPPCGlue))) != 0);
#else
gHasSpeechManager = ((feature & (1 << gestaltSpeechMgrPresent)) != 0);
#endif
}
// Check for and initialize the Speech Manager
if ((Gestalt(gestaltSpeechRecognitionVersion, &feature) == noErr) && (feature != 0))
{
#if GENERATINGCFM
// If running under the CFM, make sure that we not only have the
// Speech Recognition Manager, but also the shared library, too.
// Because of the wonders of weak linking and out of memory errors
// we need to also check to make sure there is an entrypoint in the library, too.
// We need version 1.5 or later to use the new API (a pre-release version is fine).
if ((Ptr) SROpenRecognitionSystem != (Ptr) kUnresolvedCFragSymbolAddress)
{
if (feature >= 0x00000150)
gHasSpeechRecognitionManager = true;
}
#else
if (feature >= 0x00000150)
gHasSpeechRecognitionManager = true;
#endif
}
// Initialize our AppleEvent Handling Routines
InitAppleEventRoutines();
// Setup desktop rectangle for dragging windows around
GetWMgrPort(&gWindowManagerPort);
gDeskRectangle = (**GetGrayRgn()).rgnBBox;
// Setup the default menubar
// First, create a TMenuBar so we can register commands
gMenuBar = new TMenuBar();
// Add the Macintosh menus via an MBAR resource
gMenuBar->GetNewMenuBar(rMenuBar);
// add AppleMenu items
AppendResMenu(GetMenuHandle(mApple), 'DRVR');
// …and add fonts to the font menu (if it is installed)
if (GetMenuHandle(mFont))
AppendResMenu(GetMenuHandle(mFont), 'FONT');
gCommandQueue = new TLinkedList;
OSErr err = SetupApplication();
delete gSplashWindow; // get rid of the splash screen
if (err == noErr)
{
MainEventLoop();
}
TearDownApplication();
#if qInlineInputAware
if (gHasTextServices)
(void) CloseTSMAwareApplication();
#endif
#if qUseQuickDrawGX
// Tear down QuickDrawGX
if (gHasQuickDrawGX && gQuickDrawGXClient)
{
//DisposeCommonColors();
GXExitPrinting(); // Close the new printing mgr.
GXExitGraphics(); // Deallocate all of the default structures
GXDisposeGraphicsClient(gQuickDrawGXClient);
}
#endif
if (gCommandQueue)
delete gCommandQueue;
#if qUseQC
QCDeactivate();
#endif
}
/*****************************************************************************/
void MainEventLoop(void)
{
EventRecord anEvent;
unsigned long nextTimeToCheckForEvents = 0;
while (!gDone)
{
gMenuBar->RedrawIfNeeded();
if (gHasThreadManager)
YieldToAnyThread();
if ((gRunQuantum == 0) ||
(TickCount() > nextTimeToCheckForEvents))
{
nextTimeToCheckForEvents = TickCount() + gRunQuantum;
(void) WaitNextEvent(everyEvent,&anEvent,gSleepQuantum,gMouseRegion);
#if qInlineInputAware
if (gHasTextServices && TSMEventWrapperForKotoeri(&anEvent))
{
}
else
#endif
HandleEvent(&anEvent);
}
}
}
/*****************************************************************************/
#if qInlineInputAware
Boolean TSMEventWrapperForKotoeri(EventRecord *anEvent)
{
short oldFont;
ScriptCode keyboardScript;
Boolean didTSMHandleTheEvent = false;
// This snippet of code is from TE 27: Inline Input & TextEdit
// and is related to working around a bug in Kotoeri, one of the
// Japanese Input methods when operating in a mixed script
// environment (e.g., Japanese Language Kit)
// make sure we have a port and it's not the Window Manager port
if (qd.thePort != nil)
{
oldFont = qd.thePort->txFont;
keyboardScript = GetScriptManagerVariable(smKeyScript);
if (FontToScript(oldFont) != keyboardScript)
TextFont(GetScriptVariable(keyboardScript, smScriptAppFond));
}
didTSMHandleTheEvent = TSMEvent(anEvent);
TextFont(oldFont); // restore the font, even though the sample code didn’t
return didTSMHandleTheEvent;
}
#endif
/*****************************************************************************/
void HandleEvent(EventRecord *anEvent)
{
TWindow * frontWindowObj;
if (anEvent->what != updateEvt)
frontWindowObj = GetWindowObject(FrontNonFloatingWindow());
else
frontWindowObj = GetWindowObject((WindowRef) anEvent->message);
if (frontWindowObj != nil)
#if qInlineInputAware
// give text services a chance to set the cursor shape
if (gHasTextServices && SetTSMCursor(anEvent->where))
; // do nothing, TSM did it for me
else
#endif
frontWindowObj->AdjustCursor(anEvent);
if ((frontWindowObj != nil) && frontWindowObj->EventFilter(anEvent))
return;
else switch (anEvent->what)
{
case nullEvent:
if (frontWindowObj != nil)
{
frontWindowObj->Idle(anEvent);
}
if (gCommandQueue)
{
CommandID aCommand = (CommandID)gCommandQueue->GetNthLinkObject(1);
if (aCommand != 0)
{
if (frontWindowObj == nil) // No front window? Give it to the app.
HandleCommand(aCommand);
else if (!frontWindowObj->DoCommand(aCommand)) // Give the front window a crack,
HandleCommand(aCommand); // then the app itself
gCommandQueue->FindAndDeleteLink((void *)aCommand);
}
}
break;
case mouseDown:
HandleMouseDown(frontWindowObj,anEvent);
break;
case keyDown:
case autoKey:
if (anEvent->modifiers & cmdKey)
{
if (frontWindowObj != nil)
frontWindowObj->AdjustMenusBeforeMenuSelection();
long menuResult = MenuKey((short) anEvent->message & charCodeMask);
#if qInlineInputAware
if (!(gHasTextServices && TSMMenuSelect(menuResult)))
#endif
HandleMenu(frontWindowObj,menuResult);
HiliteMenu(0);
}
else if (frontWindowObj != nil)
frontWindowObj->KeyDown(anEvent);
break;
case updateEvt:
{
GrafPtr oldPort;
WindowRef aWindow = (WindowRef) anEvent->message;
GetPort(&oldPort);
SetPortWindowPort(aWindow);
BeginUpdate(aWindow);
if (frontWindowObj != nil)
frontWindowObj->Draw();
EndUpdate(aWindow);
SetPort(oldPort);
}
break;
case diskEvt:
if (anEvent->message >> 16)
{
static Point where = {50,50};
(void) DIBadMount(where, anEvent->message);
}
break;
case osEvt:
switch ((anEvent->message & osEvtMessageMask) >> 24)
{
case mouseMovedMessage:
break;
case suspendResumeMessage:
SuspendResumeWindows((anEvent->message & resumeFlag) != 0);
if (anEvent->message & resumeFlag)
{
if (anEvent->message & convertClipboardFlag)
ReadLocalClipboardFromScrap();
gRunQuantum = gForegroundRunQuantum;
gSleepQuantum = gForegroundSleepQuantum;
}
else
{
if (anEvent->message & convertClipboardFlag)
WriteLocalClipboardToScrap();
gRunQuantum = gBackgroundRunQuantum;
gSleepQuantum = gBackgroundSleepQuantum;
}
break;
}
break;
case kHighLevelEvent:
(void) AEProcessAppleEvent(anEvent);
break;
default:
break;
}
}
/*****************************************************************************/
void HandleMouseDown(TWindow * topWindowObj,EventRecord *anEvent)
{
WindowRef aWindow;
TWindow *frontWindowObj;
short partCode;
partCode = FindWindow(anEvent->where, &aWindow);
frontWindowObj = GetWindowObject(aWindow);
switch(partCode)
{
case inMenuBar:
// Thanks mclow! FindWindow made aWindow NULL when inMenuBar!
frontWindowObj = GetWindowObject(FrontNonFloatingWindow());
if (frontWindowObj != nil)
frontWindowObj->AdjustMenusBeforeMenuSelection();
long menuResult = MenuSelect(anEvent->where);
#if qInlineInputAware
if (!(gHasTextServices && TSMMenuSelect(menuResult)))
#endif
HandleMenu(topWindowObj, menuResult);
HiliteMenu(0);
break;
case inSysWindow:
SystemClick(anEvent, aWindow);
break;
case inContent:
if (frontWindowObj != nil)
{
GrafPtr oldPort;
GetPort(&oldPort);
SetPortWindowPort(aWindow);
GlobalToLocal(&anEvent->where);
frontWindowObj->ClickAndDrag(anEvent);
SetPortWindowPort(aWindow);
}
break;
case inDrag:
if (frontWindowObj)
frontWindowObj->Drag(anEvent->where);
break;
case inGrow:
if (frontWindowObj)
frontWindowObj->Grow(anEvent->where);
break;
case inGoAway:
if (TrackGoAway(aWindow,anEvent->where))
HandleClose(aWindow);
break;
case inZoomIn:
case inZoomOut:
if (TrackBox(aWindow,anEvent->where,partCode) && (frontWindowObj))
frontWindowObj->Zoom(partCode);
break;
default:
break;
}
}
/*****************************************************************************/
void HandleClose(WindowRef aWindow)
{
short windowKind;
TWindow *frontWindowObj;
if (aWindow)
{
windowKind = GetWindowKind(aWindow);
if (windowKind < 0)
{
CloseDeskAcc(GetWindowKind(aWindow));
}
else if ( ((frontWindowObj = GetWindowObject(aWindow)) != nil) &&
frontWindowObj->CanClose(false) &&
frontWindowObj->Close() &&
frontWindowObj->DeleteAfterClose() )
{
delete frontWindowObj;
}
}
}
/*****************************************************************************/
void HandleMenu(TWindow* topWindow, long menuCode)
{
short menu = (short) (menuCode >> 16);
short item = (short) (menuCode & 0xffff);
// First, some special case menu handling for Mac OS:
// • Openning “Desk Accessories”
// • Passing Edit commands through SystemEdit.
switch (menu)
{
case mApple:
if (item != iAbout)
{
Str255 deskAccName;
GetMenuItemText(GetMenuHandle(mApple), item, deskAccName);
(void) OpenDeskAcc(deskAccName);
return;
}
break;
case mEdit:
if (SystemEdit(item-1))
return;
default:
break;
}
// Next, check to see if the menu selection is a command
CommandID command = gMenuBar->GetCommand(menu, item);
if (command)
{
if (command == cQuit)
{
TWindow* frontWindowObj;
frontWindowObj = GetWindowObject(FrontNonFloatingWindow());
while(frontWindowObj != nil)
{
if (frontWindowObj->CanClose(true) &&
frontWindowObj->Close() &&
frontWindowObj->DeleteAfterClose() )
{
delete frontWindowObj;
}
else
return; // short-circuit the quit command
frontWindowObj = GetWindowObject(FrontNonFloatingWindow());
}
gDone = QuitApplication(); // all windows closed, so give the app one final chance
return;
}
SendCommandToSelf(command); // Allow commands to be recorded
}
else
{
// If we don’t have a command, give the active window a
// chance to handle the raw menu selection.
// Windows which need to respond to dynamic menus (such as
// Font or Windows) menus should use this method.
if (topWindow)
{
if (topWindow->DoMenuSelection(menu, item))
return;
}
// No window wanted to handle the selection, go ahead
// and give the application a crack at it.
HandleMenuSelection(menu, item);
}
}
/*****************************************************************************/
OSErr QueueCommand(CommandID command)
{
OSErr err = -1;
if (gCommandQueue && command != 0)
err = gCommandQueue->CreateAndAddLink((void *)command); // just storing a CommandID here
else
DebugMessage("\pgCommandQueue is nil");
return err;
}